package com.cskaoyan.javase.oop3._2inner._4anonymous._0introduction;

/**
 * @description: 匿名内部类的使用/基本特点
 * @author: wuguidong@cskaoyan.onaliyun.com
 **/

/**
 * 我们已经使用过匿名对象了，匿名对象的含义是这个对象是没有名字，没有引用指向它
 * 那么如果一个类没有名字，那么这个类就是匿名类（Anonymous Class）
 * 显然一个正常的类是不可能没有名字的，我们今天就来介绍匿名的(局部)内部类
 *
 * 匿名内部类的语法:
 *      new 类名或者接口名(){
 *          //重写方法
 *      };
 *  匿名内部类实际上不是一个"类",而是一个目标类型的子类对象,而这个子类对象的类名是不可知的,所以是匿名名
 *  其次,这个子类对象的名字也是不可知的,所以匿名内部类,也叫匿名内部类对象
 *
 * 匿名内部类怎么用?
 *      匿名内部类的语法结构得到的是一个子类对象,所以它有两种使用方式:
 *          1,接收它,然后用对象名方式去使用
 *              接收时，必须用父类类型接收
 *              好处是可以被多次使用
 *              坏处是只能访问父类中存在的成员，而不能访问子类独有的，并且是绝对不可访问，因为无法强转
 *
 *          2,直接在后面点,当一个匿名对象用
 *              好处是使用方便快捷,其次可以访问子类独有成员
 *              缺点是只能用一次
 *
 * 以上,如果只想使用一次匿名内部类对象,建议直接使用,否则建议接收
 *
 * 细节:
 *      匿名内部类语法当中的"()"有没有用?
 *      有用,当你创建类的子类对象时,可以用()表示调用某个构造方法
 *      但是如果是接口,它就没有意义了,接口没有构造器
 *
 */
public class Demo {
    public static void main(String[] args) {
        //朴素的做法是,先定义实现类,再创建实现类对象
        collectVoice(new Cat());
        //稍微高级一点的做法,局部内部类
        class Lion extends AbstractAnimal {
            @Override
            public void shout() {
                System.out.println("嗷嗷嗷");
            }
        }
        collectVoice(new Lion());

        //更高级一点,使用匿名内部类简化以上局部内部类的代码
        //匿名内部类的语法隐含了继承,得到的是子类对象
        /*
        以下结构得到了一个AbstractAnimal子类对象
        new AbstractAnimal(){
            @Override
            public void shout() {
                System.out.println("我是高级的写法,匿名内部类");
            }
        };*/

        //1.接收使用
        AbstractAnimal aa = new AbstractAnimal() {
            @Override
            public void shout() {
                System.out.println("我是高级的写法,匿名内部类");
            }

            public void eat() {
                System.out.println("我想吃肉肉！");
            }
        };
        aa.shout();
        //((AbstractAnimal) aa).eat();

        //2.直接使用
        new AbstractAnimal() {
            @Override
            public void shout() {
                System.out.println("我是高级的写法,匿名内部类");
            }

            public void eat() {
                System.out.println("我想吃肉肉！");
            }
        }.eat();
    }

    public static void collectVoice(AbstractAnimal a) {
        a.shout();
    }
}

abstract class AbstractAnimal {
    public abstract void shout();
}

class Cat extends AbstractAnimal {
    @Override
    public void shout() {
        System.out.println("喵喵喵");
    }
}